package oojo.data.impl.exec.sub;

import java.util.List;

import javax.persistence.EntityManager;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import oojo.data.Query;
import oojo.data.QueryException;
import oojo.data.spec.sub.SubUpdate;
import oojo.data.impl.Properties;
import oojo.data.impl.SubRepositoryImpl;
import oojo.data.impl.exec.UpdateQuery;

public class SubUpdateQuery<E> extends UpdateQuery<E> {

    private static final Logger logger = LoggerFactory.getLogger(SubUpdateQuery.class);
    
    public Class<?> getQueryClass() {
        return SubUpdate.class;
    }
    
    public E execute(Query<E, E> update) {
        logger.debug("---> execute(spec)");
        
        try {
            SubUpdate<E> spec = (SubUpdate<E>) update;
            SubRepositoryImpl<E> repository = (SubRepositoryImpl<E>) getRepository();
            EntityManager entityManager = getRepository().getEntityManager();
            
            if (repository.getChildsProperty() != null) {
                
                // One-to-Many (or Many-to-Many) relation with link table.
                // We have to check for parent change, in which case
                // the link record has to be changed or dropped.
                
                // Many-to-One relations do not need such thing because
                // the link resides in the child record and is updated
                // along with the child itself.
                
                Object entityId = Properties.id(getRepository().getEntityClass(), spec.getEntity());
                E managedEntity = (E) entityManager.find(getRepository().getEntityClass(), entityId);
                
                String parentQuery = "select p from " + repository.getParentClass().getName() + " p join p." + repository.getChildsProperty() + " e where e.id = :id";
                List<?> parentList = entityManager.createQuery(parentQuery).setParameter("id", entityId).getResultList();
                
                if (parentList.size() == 1) {
                    Object oldParent = parentList.get(0);
                    Object oldParentId = Properties.id(repository.getParentClass(), oldParent);
                    
                    if (!oldParentId.equals(spec.getParentId())) {
                        repository.unlink(oldParent, managedEntity);
                    }
                }
            }
            
            if (spec.getParentId() != null) {
                Object newParent = entityManager.find(repository.getParentClass(), spec.getParentId());
                repository.link(newParent, spec.getEntity());
            }
            
            return super.execute(update);
        } catch (Exception ex) {
            throw new QueryException(ex);
        }
    }
}
